#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <sys/iofunc.h>
#include <sys/dispatch.h>
#include <time.h>
#include <sys/netmgr.h>
#include <math.h>

#include "iofuncs.h"
#include "cirbuf.h"

static	void	optproc (int, char **);
static	void	execute_resmgr ();

char			*progname  = "fast_trend";

histories_t 	*histories;

int itmp = 0;


int timer_tick (message_context_t *ctp, int code, unsigned flags, void *handle) 
{
	uint64_t start, stop;	
	int i;
	cfg_t *cfg;
	pt_t pt;

	ClockTime (CLOCK_REALTIME, NULL, &start);

	for (i= 0; i< histories->ncfg; i++) {
		cfg = &histories->cfg [i];
		pt.t = (double) start / 1000000.0;
		pt.y = (i+1) * sin ((itmp * (i+1))/ 3.14);
		cirbuf_add_pt (cfg, &pt);
	}	
	itmp ++;
	
	ClockTime (CLOCK_REALTIME, NULL, &stop);
	//printf ("time elapsed %8.3f ms\n", (double)(stop - start)/ 1000000.0);

    return 0;
}

int init_fasttrend_db (histories_t *db, char **name, int *nodeid, int *addr, int nname)
{
	int i;
	cfg_t *cfg;
	
	db->ncfg = nname;
	db->cfg = malloc (nname * sizeof (cfg_t));
	if (db->cfg == NULL) {
		db->ncfg = 0;
		return -1;
	}
	
	for (i= 0; i< nname; i++) {
		cfg = &db->cfg [i];
		cfg->point_name = strdup (name [i]);
		cfg->nodeid = nodeid [i];
		cfg->addr = addr [i];
		init_cirbuf (cfg);
	}	
	
	return 0;
}

int main (int argc, char **argv)
{
	int nname = 2;
	char *name [] = {"Ia1", "Ua1"};
	int nodeid [] = {1, 1};
	int addr [] = {0502, 0304};

	if (ThreadCtl (_NTO_TCTL_IO, 0) == -1) {
		fprintf (stderr, "%s:  can't obtain I/O privilege; ensure you are running as root! (errno %d (%s))\n", progname, errno, strerror (errno));
		exit (EXIT_FAILURE);
	}

	optproc (argc, argv);

	histories = malloc (sizeof (histories_t));
	if (histories == NULL) {
		fprintf (stderr, "Can't malloc for histories\n");
		exit (EXIT_FAILURE);
	}
	if (init_fasttrend_db (histories, name, nodeid, addr, nname) == -1) {
		fprintf (stderr, "Can't init_fasttrend_db\n");
		exit (EXIT_FAILURE);
	}

	execute_resmgr (); // never returns

	return (EXIT_SUCCESS);
}

static void execute_resmgr ()
{
	resmgr_attr_t			resmgr_attr;
	resmgr_connect_funcs_t	connect_func;
	resmgr_io_funcs_t		io_func;
	dispatch_t				*dpp;
	dispatch_context_t		*ctp;
	iofunc_attr_t			attr;

    int                   	timer_id;
    struct sigevent       	event;
    struct _itimer        	itime;
	int                   	id;
	
	//signal (SIGTERM, signal_handler);
	
	// create the dispatch structure
	if ((dpp = dispatch_create ()) == NULL) {
		perror ("Unable to dispatch_create().");
		exit (EXIT_FAILURE);
	}

	// initialize the various data structures
	memset (&resmgr_attr, 0, sizeof (resmgr_attr));
    resmgr_attr.nparts_max = 1;
    resmgr_attr.msg_max_size = 2048;
    
	// bind default functions into the outcall tables
	iofunc_func_init (_RESMGR_CONNECT_NFUNCS, &connect_func, _RESMGR_IO_NFUNCS, &io_func);
	iofunc_attr_init (&attr, S_IFNAM | 0666, 0, 0);
	attr.nbytes = 0;
	
	io_func.devctl 	= io_devctl;
	io_func.read 	= io_read;	
		
    if((id = resmgr_attach (dpp, &resmgr_attr, "/dev/fast_trend", 
                 _FTYPE_ANY, 0,
                 &connect_func, &io_func, &attr)) == -1) {
        fprintf (stderr, "Unable to attach name.\n");
        return;
    }
    
    /* Initialize an event structure, and attach a pulse to it */
    if((event.sigev_code = pulse_attach (dpp, MSG_FLAG_ALLOC_PULSE, 0, &timer_tick, NULL)) == -1) {
        fprintf (stderr, "Unable to attach timer pulse.\n");
        exit (EXIT_FAILURE);
    }
    
    /* Connect to our channel */
    if((event.sigev_coid = message_connect (dpp, MSG_FLAG_SIDE_CHANNEL)) == -1) {
        fprintf (stderr, "Unable to attach to channel.\n");
        exit (EXIT_FAILURE);
    }

    event.sigev_notify = SIGEV_PULSE;
    event.sigev_priority = -1;
    event.sigev_value.sival_int = 0;

    if((timer_id = TimerCreate (CLOCK_REALTIME, &event)) == -1) {
        fprintf (stderr, "Unable to attach channel and connection.\n");
        exit (EXIT_FAILURE);
    }

    itime.nsec = 1000000 * 100;
   	itime.interval_nsec = 1000000 * 100;

    TimerSettime (timer_id, 0, &itime, NULL);    

	ctp = dispatch_context_alloc (dpp);
		
	// wait here forever, handling messages
	while (1) {
		if (ctp = dispatch_block (ctp)) {
			dispatch_handler (ctp);
		}
	}
}

static void usageError (void)
{
	fprintf (stderr, "%s:  error in use, type \"use %s\" for usage\n", progname, progname);
	exit (EXIT_FAILURE);
}

///////////////////////////////////////////////////////////////////////////////
// Обработка опций при запуске
///////////////////////////////////////////////////////////////////////////////

static void optproc (int argc, char **argv)
{
	int opt;

	while ((opt = getopt (argc, argv, "")) != -1) {
		switch (opt) {

		default:
			usageError ();
			break;
		}
	}
}